package co.fitstart.weapp.api.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;

import co.fitstart.entity.course.CourseType;
import co.fitstart.entity.course.round.CourseRound;
import co.fitstart.entity.course.round.CourseRoundFeedback;
import co.fitstart.entity.course.round.RoundStatus;
import co.fitstart.entity.course.schedule.CourseSchedule;
import co.fitstart.entity.course.schedule.ScheduleStatus;
import co.fitstart.entity.order.Order;
import co.fitstart.entity.user.Student;
import co.fitstart.entity.user.bwh.BwhRecord;
import co.fitstart.entity.user.inbody.InbodyRecord;
import co.fitstart.weapp.api.dao.BwhRecordDao;
import co.fitstart.weapp.api.dao.CourseRoundDao;
import co.fitstart.weapp.api.dao.CourseScheduleDao;
import co.fitstart.weapp.api.dao.CoursewareDao;
import co.fitstart.weapp.api.dao.InbodyDao;
import co.fitstart.weapp.api.dao.OrderDao;
import co.fitstart.weapp.api.dao.StudentTargetDao;
import co.fitstart.weapp.api.service.CourseRoundService;

/**
 * 
 * @author haiyan_xiao
 *
 */
@Service("courseRoundService")
public class CourseRoundServiceImpl implements CourseRoundService {

    @Dao
    private CourseRoundDao courseRoundDao;

    @Autowired
    private GenericDaoSupport genericDaoSupport;

    @Dao
    private CourseScheduleDao courseScheduleDao;

    @Dao
    private OrderDao orderDao;

    @Dao
    private StudentTargetDao studentTargetDao;

    @Dao
    private InbodyDao inbodyDao;

    @Dao
    private BwhRecordDao bwhRecordDao;

    @Dao
    private CoursewareDao coursewareDao;

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#listAvailable(co.fitstart.entity.user.Student)
     */
    public List<Map<String, Object>> listAvailable(Student student) {
        List<Map<String, Object>> result = new ArrayList<>();
        
        List<CourseRound> readyCourseRounds = courseRoundDao.list(student, Arrays.asList(new CourseType[]{CourseType.INDIVIDUAL, CourseType.GROUP, CourseType.YEAR}), RoundStatus.READY);
        if(!readyCourseRounds.isEmpty()) {
            
            for(CourseRound courseRound : readyCourseRounds) {
                if(courseRound.isGive()) {
                    Map<String, Object> give = new HashMap<>();
                    give.put("courseRound", courseRound);
                    give.put("needTarget", false);
                    result.add(give);
                    
                    if(courseRound.getMainCourseRound() != null && readyCourseRounds.contains(courseRound.getMainCourseRound())) {
                        Map<String, Object> main = new HashMap<>();
                        main.put("courseRound", courseRound.getMainCourseRound());
                        main.put("needTarget", false);
                        result.add(main);
                    }
                } else if(courseRound.getGiveCourseRound() == null || !readyCourseRounds.contains(courseRound.getGiveCourseRound())) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("courseRound", courseRound);
                    map.put("needTarget", false);
                    result.add(map);
                }
            }
        }
        
        List<CourseRound> prepareCourseRounds = courseRoundDao.list(student, Arrays.asList(new CourseType[]{CourseType.INDIVIDUAL, CourseType.GROUP, CourseType.YEAR}), RoundStatus.PREPARE);
        if(!prepareCourseRounds.isEmpty()) {
            List<CourseRound> courseRounds = studentTargetDao.listCourseRound(prepareCourseRounds);
            for(CourseRound courseRound : prepareCourseRounds) {
                if(courseRound.isGive()) {
                    Map<String, Object> give = new HashMap<>();
                    give.put("courseRound", courseRound);
                    give.put("needTarget", courseRounds.contains(courseRound) ? false : courseRound.isTargetNeeded());
                    result.add(give);
                    
                    if(courseRound.getMainCourseRound() != null && prepareCourseRounds.contains(courseRound.getMainCourseRound())) {
                        Map<String, Object> main = new HashMap<>();
                        main.put("courseRound", courseRound.getMainCourseRound());
                        main.put("needTarget", courseRounds.contains(courseRound.getMainCourseRound()) ? false : courseRound.getMainCourseRound().isTargetNeeded());
                        result.add(main);
                    }
                } else if(courseRound.getGiveCourseRound() == null || !prepareCourseRounds.contains(courseRound.getGiveCourseRound())) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("courseRound", courseRound);
                    map.put("needTarget", false);
                    result.add(map);
                }
            }
        }
        
        return result;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#listUnavailable(co.fitstart.entity.user.Student)
     */
    public List<CourseRound> listUnavailable(Student student) {
        List<CourseRound> courseRounds = new ArrayList<>();
        
        courseRounds.addAll(courseRoundDao.list(student, Arrays.asList(new CourseType[]{CourseType.INDIVIDUAL, CourseType.GROUP, CourseType.YEAR}), Arrays.asList(new RoundStatus[]{RoundStatus.HOLD, RoundStatus.EXPIRE, RoundStatus.ACTIVATE})));
        courseRounds.addAll(courseRoundDao.list(student, Arrays.asList(new CourseType[]{CourseType.INDIVIDUAL, CourseType.GROUP, CourseType.YEAR}), RoundStatus.FINISH));
        
        return courseRounds;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#listOnline(co.fitstart.entity.user.Student)
     */
    public List<CourseRound> listOnline(Student student) {
        return courseRoundDao.list(student, CourseType.ONLINE, Arrays.asList(new RoundStatus[]{RoundStatus.PREPARE, RoundStatus.READY, RoundStatus.HOLD, RoundStatus.EXPIRE, RoundStatus.ACTIVATE, RoundStatus.FINISH}));
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#load(java.lang.Long)
     */
    public CourseRound load(Long courseRoundId) {
        CourseRound courseRound = genericDaoSupport.load(CourseRound.class, courseRoundId);
        return courseRound != null && !courseRound.isDisabled() ? courseRound : null;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#needTargetData(co.fitstart.entity.course.round.CourseRound)
     */
    public boolean needTargetData(CourseRound courseRound) {
        if((courseRound.getCourseType().isIndividual() || courseRound.getCourseType().isYear()) && !courseRound.getCourse().isExperience()) {
            if(courseRound.getCourseStatus().isPrepare() && studentTargetDao.load(courseRound) == null && (courseRound.getFullInTarget() == null || courseRound.getFullInTarget())) {
                return true;
            }
        }
        
        return false;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#listCourseCourseWare(co.fitstart.entity.course.round.CourseRound)
     */
    public List<CourseSchedule> listCourseCourseWare(CourseRound courseRound) {
        return courseScheduleDao.list(courseRound, Arrays.asList(new ScheduleStatus[]{ScheduleStatus.READY, ScheduleStatus.FINISH, ScheduleStatus.EXPIRY}));
    }
    
    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#list(java.util.List, boolean)
     */
    public List<CourseRound> list(List<String> couponIds, boolean finish) {
        List<Order> orders = orderDao.list(couponIds);
        
        List<CourseRound> courseRounds = new ArrayList<CourseRound>();

        if(orders == null || orders.size() == 0) {
            return null;
        } else {
            
            if(finish) {
                courseRounds = courseRoundDao.listFinishCourseRound(orders, RoundStatus.FINISH);
            } else {
                List<RoundStatus> roundStatus = Arrays.asList(new RoundStatus[]{RoundStatus.FINISH, RoundStatus.CANCEL});
                courseRounds = courseRoundDao.listUnfinishCourseRound(orders, roundStatus);
            }
            
            return courseRounds;
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#listCourseSchedule(co.fitstart.entity.course.round.CourseRound)
     */
    public List<CourseSchedule> listCourseSchedule(CourseRound courseRound) {
        List<CourseSchedule> result = new ArrayList<>();
        
        result.addAll(courseScheduleDao.listAll(courseRound, ScheduleStatus.READY));
        
        if(courseRound.getCourseType().isIndividual()) {
            result.addAll(courseScheduleDao.listAll(courseRound, Arrays.asList(new ScheduleStatus[]{ScheduleStatus.SCHEDULE, ScheduleStatus.FINISH, ScheduleStatus.EXPIRY})));
        } else {
            result.addAll(courseScheduleDao.listAll(courseRound, Arrays.asList(new ScheduleStatus[]{ScheduleStatus.FINISH, ScheduleStatus.EXPIRY})));
        }
        
        return result;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#count(co.fitstart.entity.user.Student)
     */
    public int count(Student student) {
        return courseRoundDao.count(student, RoundStatus.CANCEL);
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#validate(co.fitstart.entity.user.Student, co.fitstart.entity.course.round.CourseRound)
     */
    public void validate(Student student, CourseRound courseRound) {
        if(student == null || courseRound == null || courseRound.getStudent() != student) {
            throw new BusinessException("课程异常");
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#validate(co.fitstart.entity.user.Student, co.fitstart.entity.course.schedule.CourseSchedule)
     */
    public void validate(Student student, CourseSchedule courseSchedule) {
        if(student == null || courseSchedule == null || !courseSchedule.matches(student)) {
            throw new BusinessException("课时异常");
        }
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#couldAppoint(co.fitstart.entity.course.round.CourseRound)
     */
    public boolean couldAppoint(CourseRound courseRound) {
        if(courseRound.getCourseStatus().isPrepare() || courseRound.getCourseStatus().isReady() && courseRound.getCoach() != null) {
            if(courseRound.getEffectiveEnd() == null || courseRound.getEffectiveEnd().after(DateUtils.addMinutes(new Date(), courseRound.getCourse().isExperience() ? 90 : 60))) {
                if(courseRound.getCourseType().isIndividual()) {
                    if(courseRound.getCourseAmount() - courseScheduleDao.count(courseRound, Arrays.asList(new ScheduleStatus[]{ScheduleStatus.READY, ScheduleStatus.FINISH, ScheduleStatus.EXPIRY})) > 0) {
                        return true;
                    }
                } else if(courseRound.getCourseType().isYear()) {
                    return true;
                }
            }
        }
        
        return false;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#feedback(co.fitstart.entity.course.round.CourseRound, co.fitstart.entity.course.round.CourseRoundFeedback)
     */
    public void feedback(CourseRound courseRound, CourseRoundFeedback feedback) {
        genericDaoSupport.save(feedback.initialize(courseRound));
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#isInbodyNeeded(co.fitstart.entity.course.round.CourseRound)
     */
    public boolean isInbodyNeeded(CourseRound courseRound) {
        if(courseRound.getCourseStatus().isReady() && (courseRound.getFullInTarget() == null || courseRound.getFullInTarget())) {
            InbodyRecord inbody = inbodyDao.loadLatest(courseRound.getStudent().getUser());
            
            if(inbody == null) {
                return true;
            } else if(DateUtils.isSameDay(inbody.getRecordTimeDate(), DateUtils.addWeeks(new Date(), -2)) || inbody.getRecordTimeDate().before(DateUtils.addWeeks(new Date(), -2))) {
                return true;
            } else if(courseRound.getEffectiveStart() != null && (DateUtils.isSameDay(inbody.getRecordTimeDate(), courseRound.getEffectiveStart()) || inbody.getRecordTimeDate().before(courseRound.getEffectiveStart()))) {
                return true;
            }
        }
        
        return false;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#isBwhNeeded(co.fitstart.entity.course.round.CourseRound)
     */
    public boolean isBwhNeeded(CourseRound courseRound) {
        if(courseRound.getCourseStatus().isReady() && (courseRound.getFullInTarget() == null || courseRound.getFullInTarget())) {
            BwhRecord bwhRecord = bwhRecordDao.loadLatest(courseRound);
            
            if(bwhRecord == null || DateUtils.isSameDay(bwhRecord.getCreateTime(), DateUtils.addWeeks(new Date(), -2)) || bwhRecord.getCreateTime().before(DateUtils.addWeeks(new Date(), -2))) {
                return true;
            }
        }
        
        return false;
    }

    /*
     * (non-Javadoc)
     * @see co.fitstart.weapp.api.service.CourseRoundService#list(co.fitstart.entity.user.Student)
     */
    public List<CourseRound> list(Student student) {
        return courseRoundDao.list(student, Arrays.asList(new CourseType[]{CourseType.INDIVIDUAL, CourseType.YEAR}));
    }
}
